package com.bsg.upm.check;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.bsg.upm.constant.DictTypeConstants;
import com.bsg.upm.constant.Messages;
import com.bsg.upm.constant.SysConstants;
import com.bsg.upm.entity.SiteEntity;
import com.bsg.upm.exception.APIException;
import com.bsg.upm.http.HttpClientException;
import com.bsg.upm.http.HttpClientUtils;
import com.bsg.upm.http.HttpConnectionException;
import com.bsg.upm.http.RespJson;
import com.bsg.upm.util.IpV4Utils;
import com.google.common.net.HostAndPort;
import com.orbitz.consul.Consul;
import com.orbitz.consul.HealthClient;
import com.orbitz.consul.model.State;
import com.orbitz.consul.model.health.HealthCheck;
import com.orbitz.consul.model.health.ServiceHealth;

/**
 * 站点业务处理检查
 * 
 * @author HCK
 *
 */
@Service
public class SiteCheck extends BaseCheck {

	/**
	 * 站点新增时检查
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return CheckResult检查结果对象
	 */
	public CheckResult checkSave(Map<String, Object> paramMap) {
		// 非逻辑检查
		CheckResult chkRS = checkSaveNonLogic(paramMap);
		if (chkRS.isError()) {
			return chkRS;
		}

		// 逻辑检查
		chkRS = checkSaveLogic(paramMap);
		if (chkRS.isError()) {
			return chkRS;
		}
		return chkRS;
	}

	/**
	 * 站点删除时检查
	 * 
	 * @param site
	 *            站点对象
	 * @return CheckResult检查结果对象
	 */
	public CheckResult checkRemove(SiteEntity site) {
		CheckResult chkRS = new CheckResult();
		// 存在性检查
		if (site == null) {
			chkRS.setStatus(HttpStatus.SC_GONE);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NOT_EXIST, "站点"));
			return chkRS;
		}

		if (backupStorageDao.countBySiteId(site.getId()) > 0) {
			chkRS.setStatus(HttpStatus.SC_CONFLICT);
			chkRS.setErrorMsg("该站点已关联备份存储，无法删除");
			return chkRS;
		}

		if (networkingDao.countBySiteId(site.getId()) > 0) {
			chkRS.setStatus(HttpStatus.SC_CONFLICT);
			chkRS.setErrorMsg("该站点已关联网段，无法删除");
			return chkRS;
		}

		if (portDao.countBySiteId(site.getId()) > 0) {
			chkRS.setStatus(HttpStatus.SC_CONFLICT);
			chkRS.setErrorMsg("该站点已关联端口，无法删除");
			return chkRS;
		}

		if (sanDao.countBySiteId(site.getId()) > 0) {
			chkRS.setStatus(HttpStatus.SC_CONFLICT);
			chkRS.setErrorMsg("该站点已关联SAN，无法删除");
			return chkRS;
		}

		return chkRS;
	}

	/**
	 * 新增时非业务逻辑(非空和长度)检查
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return CheckResult检查结果对象
	 */
	private CheckResult checkSaveNonLogic(Map<String, Object> paramMap) {
		CheckResult chkRS = new CheckResult();

		// 站点名称非空和长度检查
		String name = (String) paramMap.get("name");
		if (StringUtils.isBlank(name)) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "站点名称"));
			return chkRS;
		}
		if (StringUtils.trim(name).length() > 64) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg(MessageFormat.format(Messages.MAXLENGTH_NOT_ALLOWED, "站点名称", 64));
			return chkRS;
		}

		// 地域非空检查
		String regionCode = (String) paramMap.get("regionCode");
		if (StringUtils.isBlank(regionCode)) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "地域"));
			return chkRS;
		}

		// consul地址非空检查
		String consulIps = (String) paramMap.get("consulIps");
		if (StringUtils.isBlank(consulIps)) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "consul地址"));
			return chkRS;
		}

		// consul端口非空检查
		Integer consulPort = (Integer) paramMap.get("consulPort");
		if (consulPort == null) {
			chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NULL_NOT_ALLOWED, "consul端口"));
			return chkRS;
		}

		return chkRS;
	}

	/**
	 * 新增时业务逻辑检查
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return CheckResult检查结果对象
	 * @throws APIException
	 * @throws HttpClientException
	 */
	private CheckResult checkSaveLogic(Map<String, Object> paramMap) {
		CheckResult chkRS = new CheckResult();

		// 站点名称重复性检查
		String name = (String) paramMap.get("name");
		if (siteDao.countByName(name) > 0) {
			chkRS.setStatus(HttpStatus.SC_CONFLICT);
			chkRS.setErrorMsg(MessageFormat.format(Messages.EXIST, "站点名称"));
			return chkRS;
		}

		// 地域存在性检查
		String regionCode = (String) paramMap.get("regionCode");
		if (dictTypeCache.getDictFromCache(DictTypeConstants.REGION, regionCode) == null) {
			chkRS.setStatus(HttpStatus.SC_GONE);
			chkRS.setErrorMsg(MessageFormat.format(Messages.NOT_EXIST, "地域"));
			return chkRS;
		}

		// consul地址有效性检查
		String consulIps = (String) paramMap.get("consulIps");
		String[] consulIpArr = consulIps.split(",");
		for (String ip : consulIpArr) {
			if (StringUtils.isBlank(ip) || !IpV4Utils.ipV4Validate(ip)) {
				chkRS.setStatus(HttpStatus.SC_BAD_REQUEST);
				chkRS.setErrorMsg("consul地址错误");
				return chkRS;
			}
		}

		Integer consulPort = (Integer) paramMap.get("consulPort");
		List<String> managerHttpUrls = listAddrFromConsul(consulIps, consulPort, "MG");
		if (managerHttpUrls == null) {
			chkRS.setStatus(HttpStatus.SC_SERVICE_UNAVAILABLE);
			chkRS.setErrorMsg("consul网络连接异常");
			return chkRS;
		}

		if (managerHttpUrls.size() == 0) {
			chkRS.setStatus(HttpStatus.SC_SERVICE_UNAVAILABLE);
			chkRS.setErrorMsg("从consul上获取不到MGM地址");
			return chkRS;
		}

		List<String> monitorHttpUrls = listAddrFromConsul(consulIps, consulPort, "HS");
		if (monitorHttpUrls.size() == 0) {
			chkRS.setStatus(HttpStatus.SC_SERVICE_UNAVAILABLE);
			chkRS.setErrorMsg("从consul上获取不到HORUS地址");
			return chkRS;
		}

		try {
			Arrays.sort(consulIpArr);

			for (String managerHttpUrl : managerHttpUrls) {
				String httpUrl = managerHttpUrl + "/configs/system";
				RespJson respJson = HttpClientUtils.sendHttpGet(httpUrl, true);
				if (respJson.getStatus() != HttpStatus.SC_OK) {
					chkRS.setStatus(HttpStatus.SC_SERVICE_UNAVAILABLE);
					chkRS.setErrorMsg("MGM网络连接异常");
					return chkRS;
				}
				JSONObject configJson = (JSONObject) respJson.getData();
				String consul_ips = configJson.getString("consul_ip");
				if (StringUtils.isBlank(consul_ips)) {
					chkRS.setStatus(HttpStatus.SC_SERVICE_UNAVAILABLE);
					chkRS.setErrorMsg("MGM系统参数匹配失败：consul地址匹配失败");
					return chkRS;
				}

				String[] consul_ipArr = consul_ips.split(",");
				Arrays.sort(consul_ipArr);
				if (!Arrays.equals(consulIpArr, consul_ipArr)) {
					chkRS.setStatus(HttpStatus.SC_SERVICE_UNAVAILABLE);
					chkRS.setErrorMsg("MGM系统参数匹配失败：consul地址匹配失败(系统参数：" + consul_ips + "; 注册参数： " + consulIps);
					return chkRS;
				}

				Integer consul_port = configJson.getInteger("consul_port");
				if (consul_port == null || !consulPort.equals(consul_port)) {
					chkRS.setStatus(HttpStatus.SC_SERVICE_UNAVAILABLE);
					chkRS.setErrorMsg("MGM系统参数匹配失败：consul端口匹配失败(系统参数：" + consul_port + "; 注册参数： " + consulPort);
					return chkRS;
				}
			}

		} catch (com.bsg.upm.http.HttpClientException e) {
			e.printStackTrace();
			chkRS.setStatus(HttpStatus.SC_SERVICE_UNAVAILABLE);
			chkRS.setErrorMsg("网络连接异常");
			return chkRS;
		} catch (com.bsg.upm.http.HttpConnectionException e) {
			e.printStackTrace();
			chkRS.setStatus(HttpStatus.SC_SERVICE_UNAVAILABLE);
			chkRS.setErrorMsg("网络连接异常");
			return chkRS;
		}

		try {
			for (String monitorHttpUrl : monitorHttpUrls) {
				String httpUrl = monitorHttpUrl + "/" + SysConstants.HS_VERSION + "/_ping";
				RespJson respJson = HttpClientUtils.sendHttpGet(httpUrl, true);
				if (respJson.getStatus() != HttpStatus.SC_OK) {
					chkRS.setStatus(HttpStatus.SC_SERVICE_UNAVAILABLE);
					chkRS.setErrorMsg("HORUS网络连接异常");
					return chkRS;
				}
			}
		} catch (HttpConnectionException e) {
			chkRS.setStatus(HttpStatus.SC_SERVICE_UNAVAILABLE);
			chkRS.setErrorMsg("网络连接异常");
			return chkRS;
		} catch (HttpClientException e) {
			e.printStackTrace();
			chkRS.setStatus(HttpStatus.SC_SERVICE_UNAVAILABLE);
			chkRS.setErrorMsg("网络连接异常");
			return chkRS;
		}

		return chkRS;
	}

	private List<String> listAddrFromConsul(String consulIps, int consulPort, String prefix) {
		List<String> addrs = new ArrayList<String>();
		String[] consulIpArr = consulIps.split(",");
		Consul consul = null;
		for (String consulIp : consulIpArr) {
			HostAndPort hostAndPort = HostAndPort.fromParts(consulIp, consulPort);
			try {
				consul = Consul.builder().withHostAndPort(hostAndPort).build();
				break;
			} catch (Exception e) {
				logger.error("consul: " + consulIp + "连接异常");
			}
		}
		if (consul == null) {
			return null;
		}
		HealthClient healthClient = consul.healthClient();
		List<HealthCheck> healthChecks = healthClient.getChecksByState(State.PASS).getResponse();
		for (HealthCheck healthCheck : healthChecks) {
			if (healthCheck.getServiceName().get().startsWith(prefix)) {
				List<ServiceHealth> serviceHealths = healthClient
						.getHealthyServiceInstances(healthCheck.getServiceName().get()).getResponse();
				for (ServiceHealth serviceHealth : serviceHealths) {
					if (serviceHealth.getService().getService().equals(healthCheck.getServiceName().get())) {
						String manageHttpUrl = "http://" + serviceHealth.getService().getAddress() + ":"
								+ serviceHealth.getService().getPort();
						addrs.add(manageHttpUrl);
					}
				}
			}
		}
		return addrs;
	}

}
